package com.yupi.yupicturebackend.manager.upload;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.CIObject;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import com.yupi.yupicturebackend.config.CosClientConfig;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.manager.CosManager;
import com.yupi.yupicturebackend.model.dto.picture.UploadPictureResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * 之前虽然我们已经编写了通用的对象存储操作类 CosManager，但这个类并不能直接满足我们的图片上传需求。
 * 比如：
 * 图片是否符合要求？需要校验
 * 将图片上传到哪里？需要指定路径
 * 如何解析图片？需要使用数据万象服务
 */
@Slf4j
@Service
public abstract class PictureUploadTemplate {

    @Resource
    private CosClientConfig cosClientConfig;

    @Resource
    private CosManager cosManager;

    public UploadPictureResult uploadPicture(Object inputSource, String uploadPathPrefix){
        // 1. 校验图片
        /*
        validPicture(multipartFile);
        validPicture(fileUrl);
        */
        String contentType = validPicture(inputSource);

        // 2. 构造上传图路径 /前缀/日期+uuid+文件名.文件格式
        String uuid = RandomUtil.randomString(16);
        // 获取文件原名
        /*
        String originalFilename = multipartFile.getOriginalFilename();
        String originalFilename = FileUtil.getName(fileUrl);
        */
        String originFilename = getOriginFilename(inputSource);
        String fileSuffix = FileUtil.getSuffix(originFilename);
        String date = DateUtil.formatDate(new Date());
        String uploadFilename = null;
        // 解决了 url 上传没有后缀的问题
        if ("".equals(contentType)){
            uploadFilename = String.format("%s_%s.%s", date, uuid, fileSuffix);
        } else {
            uploadFilename = String.format("%s_%s.%s", date, uuid, contentType);
        }


        String uploadFilepath = String.format("/%s/%s", uploadPathPrefix, uploadFilename);
        // 3. 上传到COS
        File tempFile = null;
        try {
            // 3.1. 创建临时文件
            tempFile = File.createTempFile(uploadFilepath, null);
            // 处理文件来源 将文件转换到临时文件中通过零食文件上传
            /*
            multipartFile.transferTo(tempFile);
            HttpUtil.downloadFile(fileUrl, tempFile);
            */
            processFile(inputSource, tempFile);
            // 3.2. 上传文件 获取到图片信息结果
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadFilepath, tempFile);
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo(); // 获取图片信息
            List<CIObject> objectList = putObjectResult.getCiUploadResult().getProcessResults().getObjectList();
            if (CollUtil.isNotEmpty(objectList)){
                CIObject compressedCiObject = objectList.get(0);
                CIObject thumbanulCiObject = compressedCiObject;
                if (objectList.size() > 1){
                    thumbanulCiObject = objectList.get(1);
                }
                // 封装压缩图返回结果
                return buildResult(originFilename, compressedCiObject, thumbanulCiObject,imageInfo);
            }
            // 3.3. 构造返回对象
            return buildResult(originFilename, tempFile, uploadFilepath, imageInfo);
        } catch (Exception e) {
            log.error("图片上传到存储对象失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "图片上传失败");
        } finally {
            if (tempFile != null){
                boolean delete = tempFile.delete();
                if (!delete){
                    log.error("图片删除失败 uploadFilepath = {}", uploadFilepath);
                }
            }
        }
    }

    private UploadPictureResult buildResult(String originFilename, CIObject compressedCiObject, CIObject thumbanulCiObject, ImageInfo imageInfo) {
        // 3.3.1. 计算图片宽高比
        int picWidth = compressedCiObject.getWidth();
        int picHeight = compressedCiObject.getHeight();
        double scale = (picWidth * 1.0 / picHeight);
        // 3.3.2 构造返回对象
        UploadPictureResult uploadPictureResult = new UploadPictureResult();
        // 图片压缩后的地址
        uploadPictureResult.setUrl(cosClientConfig.getHost() + "/" + compressedCiObject.getKey());
        uploadPictureResult.setPicName(FileUtil.mainName(originFilename));
        uploadPictureResult.setPicSize(compressedCiObject.getSize().longValue());
        uploadPictureResult.setPicWidth(picWidth);
        uploadPictureResult.setPicHeight(picHeight);
        uploadPictureResult.setPicScale(scale);
        uploadPictureResult.setPicFormat(compressedCiObject.getFormat());
        uploadPictureResult.setPicColor(imageInfo.getAve());
        // 主页图片缩略图路径
        uploadPictureResult.setThumbnailUrl(cosClientConfig.getHost() + "/" + thumbanulCiObject.getKey());
        return uploadPictureResult;
    }

    private UploadPictureResult buildResult(String originFilename, File tempFile, String uploadFilepath, ImageInfo imageInfo) {

        // 3.3.1. 计算图片宽高比
        int picWidth = imageInfo.getWidth();
        int picHeight = imageInfo.getHeight();
        double scale = (picWidth * 1.0 / picHeight);
        // 3.3.2 构造返回对象
        UploadPictureResult uploadPictureResult = new UploadPictureResult();
        uploadPictureResult.setUrl(cosClientConfig.getHost() + uploadFilepath);
        uploadPictureResult.setPicName(FileUtil.mainName(originFilename));
        uploadPictureResult.setPicSize(FileUtil.size(tempFile));
        uploadPictureResult.setPicWidth(picWidth);
        uploadPictureResult.setPicHeight(picHeight);
        uploadPictureResult.setPicScale(scale);
        uploadPictureResult.setPicFormat(imageInfo.getFormat());
        uploadPictureResult.setPicColor(imageInfo.getAve());
        return uploadPictureResult;
    }

    protected abstract void processFile(Object inputSource, File tempFile) throws IOException;

    protected abstract String getOriginFilename(Object inputSource);

    protected abstract String validPicture(Object inputSource);
}
